package com.coocaa.cirrus.common.base.util;

import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Callable;

/**
 * @author bijiahao
 * @date : 2025/7/15 16:20
 * @description
 */
@Slf4j
@UtilityClass
public class RetryUtil {

    /**
     * 同步重试，失败包装成 RuntimeException
     */
    public static <T> T callWithThrow(String key,
                                      Callable<T> callable,
                                      int maxAttempts,
                                      long sleepMs) {
        try {
            return call(key, callable, maxAttempts, sleepMs);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void runWithThrow(String key, Runnable runnable, int maxRetryTimes, int sleepMs) {
        try {
            run(key, runnable, maxRetryTimes, sleepMs);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void run(String key, Runnable runnable, int maxRetryTimes, int sleepMs) throws Exception {
        // 借助 call 实现
        call(key, () -> {
            runnable.run();
            return null;
        }, maxRetryTimes, sleepMs);
    }

    private static <T> T call(String key,
                              Callable<T> callable,
                              int maxAttempts,
                              long sleepMs) throws Exception {
        if (maxAttempts <= 1) {
            return callable.call();
        }
        Exception lastEx = null;
        for (int i = 1; i <= maxAttempts; i++) {
            try {
                return callable.call();
            } catch (Exception ex) {
                lastEx = ex;
                log.info("[RetryUtil#call] key:{}，retryTimes:{}", key, i);
                if (i == maxAttempts) {
                    break;
                }
                if (sleepMs > 0) {
                    Thread.sleep(sleepMs);
                }
            }
        }
        throw lastEx;
    }
}
